💡 AI 인사이트

🤖 AI가 여기에 결과를 출력합니다...

댓글 커뮤니티

쿠팡이벤트

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

검색

    로딩 중이에요... 🐣

    [코담] 웹개발·실전 프로젝트·AI까지, 파이썬·장고의 모든것을 담아낸 강의와 개발 노트

    21 데이터클래스사용 | ✅ 저자: 이유정(박사)

    Data Class란? Python의 @dataclass는 데이터 저장용 클래스를 짧고 간단하게 만들 수 있도록 도와주는 기능입니다.

    • 원래 클래스는 __init__, __repr__, __eq__ 같은 메서드를 직접 작성해야 했습니다.
    • 그런데 @dataclass를 붙이면, 그런 귀찮은 코드를 자동으로 만들어줍니다!
    1. __init__: 객체가 생성될 때 실행되는 메서드( 읽기: 던더 이닛)
    class Item:
        def __init__(self, name, price):
            self.name = name
            self.price = price
    

    역할:

    • 클래스로 객체를 만들 때 자동으로 호출되는 생성자입니다.
    • Item("사과", 1000)처럼 클래스를 호출하면 __init__()이 실행되어 nameprice를 저장합니다.

    비유:

    "아이템을 만들 때 이름표와 가격표를 붙여주는 역할"

    1. __repr__: 객체를 출력할 때 보여줄 문자열을 정의 ( 읽기: 던더 래퍼)
    class Item:
        def __init__(self, name, price):
            self.name = name
            self.price = price
    
        def __repr__(self):
            return f"Item(name={self.name}, price={self.price})"
    
    item = Item("사과", 1000)
    print(item)
    

    출력결과:

    Item(name=사과, price=1000)
    
    • print(item) → 내부적으로는 item.__repr__()을 호출함.
    • __repr__()에서 f"Item(name={self.name}, price={self.price})"를 반환함.
    • 즉, 문자열로 변환해서 보여주는 거예요.

    만약 __repr__가 없다면:

    class Item:
        def __init__(self, name, price):
            self.name = name
            self.price = price
    
    item = Item("사과", 1000)
    print(item)
    

    출력결과:

    <__main__.Item object at 0x7fc4b7d4dbb0>
    

    즉, 메모리 주소만 보이는 기본 객체원형 출력 형태가 나와요.

    역할:

    • print(item) 또는 디버깅할 때, 객체의 내용을 사람이 읽기 쉽게 보여줍니다.
    • __str__()와 비슷하지만 __repr__()은 디버깅용으로 더 정밀한 표현을 목표로 합니다.

    비유:

    "출력할 때 예쁘게 보여주는 명함"


    1. __eq__: 객체끼리 같은지 비교할 때 사용 (읽기:던더 이퀄)
    class Item:
        def __init__(self, name, price):
            self.name = name
            self.price = price
    
        def __eq__(self, other):
            return self.name == other.name and self.price == other.price
    
    # 두 개의 인스턴스를 비교
    item1 = Item("Notebook", 1000)
    item2 = Item("Notebook", 1000)
    item3 = Item("Pen", 500)
    
    print(item1 == item2)  # True
    print(item1 == item3)  # False
    

    출력결과:

    True
    False
    
    • == 연산자는 내부적으로 __eq__() 메서드를 호출합니다.
    • item1 == item2일 때, 두 객체의 nameprice가 같으므로 True.
    • item1 == item3일 때, name이나 price 중 하나라도 다르므로 False.

    역할:

    • item1 == item2처럼 비교할 때 내용이 같은지 판단하는 기준을 정의합니다.
    • 기본값은 두 객체의 메모리 주소를 비교하지만, __eq__을 재정의하면 으로 비교할 수 있습니다.

    비유:

    "이 두 사람이 같은 사람인지 확인하는 신분증 검사"


    예시로 이해해보기 Python에서 사용되는 일반 클래스 (귀찮음)

    class Item:
        def __init__(self, name, price):
            self.name = name
            self.price = price
    
        def __repr__(self):
            return f"Item(name={self.name}, price={self.price})"
    

    Python에서 데이터를 담는 클래스를 더 간단히 만들고 싶을 때 – Data Class (간단함!)

    from dataclasses import dataclass
    
    @dataclass
    class Item:
        name: str
        price: float
    

    @dataclass를 사용하면 __init__, __repr__, __eq__ 같은 메서드를 자동으로 생성해주기 때문에 코드가 훨씬 간단해지고, 데이터 중심 객체를 만들기 쉬워집니다.

    왜 필요한가? 코드 간결함 : init, repr 안 써도 됨 테스트 쉬움 : 비교, 출력, 변환이 편리 가독성 좋음 : 순수 데이터 구조를 깔끔하게 표현 자동 기능 : 타입 힌트 + 기본값 + 비교 연산 다 자동 제공


    기본 Data Class 예제

    예제: 책(Book) 정보를 담는 클래스

    # book_test.py
    from dataclasses import dataclass
    
    # 책의 정보를 담는 데이터 클래스 정의
    @dataclass
    class Book:
        title: str
        author: str
        price: float
    
    # 객체 생성
    book = Book("데이터 클래스란?", "이상한 나라의 코딩", 15.99)
    
    # 출력해보기
    print(book)
    

    실행 결과:

    Book(title='데이터 클래스란?', author='이상한 나라의 코딩', price=15.99)
    

    복잡한 __init__, __repr__ 같은 함수 없이 깔끔하게 클래스 정의 가능!


    Data Class + 기본값 지정 예제: price, in_stock에 기본값을 줌

    # product_test.py
    from dataclasses import dataclass
    
    @dataclass
    class Product:
        name: str
        price: float = 0.0         # 기본값: 0.0
        in_stock: bool = True      # 기본값: True
    
    item = Product("USB")
    print(item)
    

    실행결과:

    Product(name='USB', price=0.0, in_stock=True)
    

    생성자에서 name만 넣어도 나머지는 기본값으로 자동 설정!


    FastAPI에서 요청 데이터를 Data Class로 받기 FastAPI에서 @dataclass를 사용하면 POST 요청으로 들어온 JSON 데이터를 객체로 변환해줍니다.

    예제: 상품 등록 API

    # item.py
    from dataclasses import dataclass
    from typing import Union
    from fastapi import FastAPI
    from fastapi import Body
    
    app = FastAPI()
    
    # 상품 정보를 담는 데이터 클래스
    @dataclass
    class Item:
        name: str
        price: float
        description: Union[str, None] = None
    
    @app.post("/items/")
    async def create_item(item: Item = Body(...)):
        return item
    

    실행:

    uvicorn item:app --reload
    

    브라우저에서 http://localhost:8000/docs 접속 /items/ POST 테스트 → 아래와 같은 JSON 입력

    # 요청
    {
      "name": "키보드",
      "price": 39.99,
      "description": "기계식 키보드"
    }
    
    # 응답
    {
      "name": "키보드",
      "price": 39.99,
      "description": "기계식 키보드"
    }
    

    FastAPI에서 응답을 Data Class로 반환

    @dataclass를 사용해도 response_model로 응답 스키마를 정의할 수 있습니다.

    # items.py
    # Python의 dataclass 기능과 필드 설정 도구를 불러옴
    from dataclasses import dataclass, field
    
    # 타입 힌트를 위한 도구들 불러옴 (리스트, 선택적 값)
    from typing import List, Union
    
    # FastAPI 앱을 만들기 위한 객체 불러옴
    from fastapi import FastAPI
    
    # FastAPI 인스턴스 생성 → 이걸 기준으로 API 라우터 등록 가능
    app = FastAPI()
    
    # 데이터 클래스 정의 시작: 자동으로 __init__, __repr__ 등을 생성해줌
    @dataclass
    class Item:
        # 이름: 문자열 (필수)
        name: str
        # 가격: 실수형 숫자 (필수)
        price: float
        # 태그: 문자열 리스트, 기본값은 빈 리스트
        tags: List[str] = field(default_factory=list)
        # 설명: 문자열 또는 None 가능 (기본값은 None)
        description: Union[str, None] = None
    
    # /items/ 경로에 대한 GET 요청 처리 함수 정의
    # 응답 형식을 Item 데이터클래스로 지정 (자동으로 스키마 생성됨)
    @app.get("/items/", response_model=Item)
    async def get_item():
        # 실제 반환할 데이터 딕셔너리 (Item 구조와 일치)
        return {
            "name": "Python 책",
            "price": 29.99,
            "description": "초보자를 위한 FastAPI",
            "tags": ["프로그래밍", "API"]
        }
    

    실행:

    uvicorn items:app --reload
    

    /items/에 GET 요청 시 JSON 응답:

    {
      "name": "Python 책",
      "price": 29.99,
      "description": "초보자를 위한 FastAPI",
      "tags": ["프로그래밍", "API"]
    }
    

    이 코드는 FastAPI에서 @dataclass를 활용해 응답 모델을 정의하고, /items/ 경로로 요청하면 해당 데이터를 JSON 형식으로 반환하는 API를 만드는 예시입니다.


    중첩된 Data Class 사용 (복잡한 구조도 가능) 예제: 작가(Author)와 책(Book)의 관계 표현

    # books.py
    # 필요한 모듈들을 불러옵니다.
    from dataclasses import dataclass, field          # 데이터 클래스를 만들기 위한 데코레이터와 필드 도구
    from typing import List, Union                    # 타입 힌트를 위해 리스트, 유니언 타입 사용
    from fastapi import FastAPI                       # FastAPI 애플리케이션 생성에 필요한 모듈
    
    # FastAPI 애플리케이션 인스턴스를 생성합니다.
    app = FastAPI()
    
    # Book 클래스: 책 정보를 담는 데이터 클래스입니다.
    # title은 필수(str), description은 선택(str 또는 None)
    @dataclass
    class Book:
        title: str   # 책 제목
        description: Union[str, None] = None # 책 설명 (없을 수도 있음)
    
    # Author 클래스: 작가 정보를 담고, 여러 권의 책(Book)을 가질 수 있습니다.
    @dataclass
    class Author:
        name: str  # 작가 이름
        books: List[Book] = field(default_factory=list)  
        # 작가가 쓴 책들 리스트 (기본은 빈 리스트)
    
    # GET 요청을 받을 수 있는 엔드포인트 "/authors/" 생성
    # 응답(response_model)은 Author의 리스트 형태로 정의합니다.
    @app.get("/authors/", response_model=List[Author])
    async def get_authors():
        # 작가 정보와 그들이 쓴 책들을 반환합니다. (딕셔너리 형태로 작성)
        return [
            {
                "name": "이정수", # 작가 이름
                "books": [ # 이 작가가 쓴 책들
                    {"title": "Python 개론", "description": "입문자를 위한 책"},
                    {"title": "FastAPI 완전정복"}  
                    # description은 생략해도 None으로 처리됨
                ]
            }
        ]
    

    실행:

    uvicorn books:app --reload
    

    /authors/ GET 요청 결과:

    [
      {
        "name": "이정수",
        "books": [
          {
            "title": "Python 개론",
            "description": "입문자를 위한 책"
          },
          {
            "title": "FastAPI 완전정복",
            "description": null
          }
        ]
      }
    ]
    

    데이터 구조가 복잡해도 @dataclass로 직관적으로 정의 가능!

    TOP
    preload preload